﻿using System;
using System.ComponentModel;
using System.Data;
using System.Data.SqlClient;
using System.Net.Mail;

namespace Autorun
{


	[Serializable()]
	public sealed class ConfigurationManagement : MarshalByRefObject
	{
		#region "Constants"
		private const string REMOTE_PORT = "RemotePort";
		private const string REMOTE_CHANNEL = "RemoteChannel";
		private const string THREAD_POOL_SIZE = "ThreadPoolSize";
		private const string SLEEP_TIME = "SleepTime";
		private const string PROCESS_PASSED_TASKS = "ProcessPassedTasks";
		private const string PROCESS_STARTUP_TASKS = "ProcessStartupTasks";
		private const string PROCESS_SHUTDOW_TASKS = "ProcessShutdownTasks";
		private const string SMTP_SERVER = "SmtpServer";
		private const string SMTP_PORT = "SmtpPort";
		private const string MAIL_FROM = "MailFrom";
		private const string MAIL_TO = "MailTo";
		private const string SEND_AS_HTML = "SendAsHTML";
		private const string SEND_SERVICE_STATUS = "SendServiceStatus";
		private const string SEND_TASK_REPORT = "SendTaskReport";
		private const string SEND_DAILY_REPORT = "SendDailyReport";
		private const string SMTP_DELIVERY_METHOD = "DeliveryMethod";
		private const string SMTP_PICKUP_DIRECTORY = "PickupDirectoryLocation";
		#endregion

		#region "Private members"
		private int _remotePort;
		private string _remoteChannel;
		private int _threadPoolSize;
		private int _sleepTime;
		private bool _processStartupTasks;
		private bool _processShutdownTasks;
		private bool _processPassedTasks;
		private string _smtpServer;
		private int _smtpPort;
		private SmtpDeliveryMethod _smtpDeliveryMethod;
		private string _smtpPickupDirectoryLocation;
		private string _mailFrom;
		private string _mailTo;
		private bool _sendAsHtml;
		private bool _sendServiceStatus;
		private SendTaskReportModes _sendTaskReport;
		private SendDailyReportModes _sendDailyReport;
		#endregion

		#region "Singleton Design-Pattern"
		private static ConfigurationManagement _instance = new ConfigurationManagement();

		public static ConfigurationManagement Instance
		{
			get { return _instance; }
		}

		public ConfigurationManagement()
		{
			_remotePort = int.Parse(GetSetting(REMOTE_PORT, 8085));
			_remoteChannel = GetSetting(REMOTE_CHANNEL, "TCP");
			_threadPoolSize = int.Parse(GetSetting(THREAD_POOL_SIZE, 5));
			_sleepTime = int.Parse(GetSetting(SLEEP_TIME, 1));
			_processStartupTasks = bool.Parse(GetSetting(PROCESS_STARTUP_TASKS, true));
			_processShutdownTasks = bool.Parse(GetSetting(PROCESS_SHUTDOW_TASKS, true));
			_processPassedTasks = bool.Parse(GetSetting(PROCESS_PASSED_TASKS, true));
			_smtpServer = GetSetting(SMTP_SERVER, "127.0.0.1");
			_smtpPort = int.Parse(GetSetting(SMTP_PORT, 25));
			_smtpDeliveryMethod = (SmtpDeliveryMethod)int.Parse(GetSetting(SMTP_DELIVERY_METHOD, (int)SmtpDeliveryMethod.Network));
			_smtpPickupDirectoryLocation = GetSetting(SMTP_PICKUP_DIRECTORY, null);
			_mailFrom = GetSetting(MAIL_FROM, "user@domain.com");
			_mailTo = GetSetting(MAIL_TO, "user@domain.com");
			_sendAsHtml = bool.Parse(GetSetting(SEND_AS_HTML, false));
			_sendServiceStatus = bool.Parse(GetSetting(SEND_SERVICE_STATUS, false));
			_sendTaskReport = (SendTaskReportModes)int.Parse(GetSetting(SEND_TASK_REPORT, (int)SendTaskReportModes.Never));
			_sendDailyReport = (SendDailyReportModes)int.Parse(GetSetting(SEND_DAILY_REPORT, (int)SendDailyReportModes.Never));
		}
		#endregion

		#region "Remoting Information"
		[Category("Remoting Information"), Description("This is the port on which the remote service will answer to client requests.")]
		public int RemotePort
		{
			get { return _remotePort; }
			set
			{
				if (_remotePort != value)
				{
					_remotePort = value;
					SaveSetting(REMOTE_PORT, _remotePort);
				}
			}
		}

		[Category("Remoting Information"), Description("This is the protocol on which the remote service is bound to client requests.")]
		public string RemoteChannel
		{
			get { return _remoteChannel; }
			set
			{
				if (_remoteChannel != value)
				{
					_remoteChannel = value;
					SaveSetting(REMOTE_CHANNEL, _remoteChannel);
				}
			}
		}
		#endregion

		#region "Service Information"
		[Category("Service Information"), Description("Number of tasks that can run at the same time.")]
		public int ThreadPoolSize
		{
			get { return _threadPoolSize; }
			set
			{
				if (_threadPoolSize != value)
				{
					_threadPoolSize = value;
					SaveSetting(THREAD_POOL_SIZE, _threadPoolSize);
				}
			}
		}

		[Category("Service Information"), Description("Time (in seconds) the main thread must be idled when no work to be done. This is used to limit the processor's activity.")]
		public int SleepTime
		{
			get { return _sleepTime; }
			set
			{
				if (_sleepTime != value)
				{
					_sleepTime = value;
					SaveSetting(SLEEP_TIME, _sleepTime);
				}
			}
		}
		#endregion

		#region "Scheduler Information"
		[Category("Scheduler Information"), Description("When the service is started, should the scheduler plan tasks that should have been planned before the start time?")]
		public bool ProcessPassedTasks
		{
			get { return _processPassedTasks; }
			set
			{
				if (_processPassedTasks != value)
				{
					_processPassedTasks = value;
					SaveSetting(PROCESS_PASSED_TASKS, _processPassedTasks);
				}
			}
		}

		[Category("Scheduler Information"), Description("When the service is started, should the scheduler plan tasks that should run at startup?")]
		public bool ProcessStartupTasks
		{
			get { return _processStartupTasks; }
			set
			{
				if (_processStartupTasks != value)
				{
					_processStartupTasks = value;
					SaveSetting(PROCESS_STARTUP_TASKS, _processStartupTasks);
				}
			}
		}

		[Category("Scheduler Information"), Description("When the service is started, should the scheduler plan tasks that should run at shutdown?")]
		public bool ProcessShutdownTasks
		{
			get { return _processShutdownTasks; }
			set
			{
				if (_processShutdownTasks != value)
				{
					_processShutdownTasks = value;
					SaveSetting(PROCESS_SHUTDOW_TASKS, _processShutdownTasks);
				}
			}
		}
		#endregion

		#region "Reporting Information"
		[Category("Reporting Information"), Description("URI of the SMTP server.")]
		public string SmtpServer
		{
			get { return _smtpServer; }
			set
			{
				if (_smtpServer != value)
				{
					_smtpServer = value;
					SaveSetting(SMTP_SERVER, _smtpServer);
				}
			}
		}

		[Category("Reporting Information"), Description("Port of the SMTP server.")]
		public int SmtpPort
		{
			get { return _smtpPort; }
			set
			{
				if (_smtpPort != value)
				{
					_smtpPort = value;
					SaveSetting(SMTP_PORT, _smtpPort);
				}
			}
		}

		[Category("Reporting Information"), Description("Delivery method for SMTP server.")]
		public SmtpDeliveryMethod SmtpDeliveryMethod
		{
			get { return _smtpDeliveryMethod; }
			set
			{
				if (_smtpDeliveryMethod != value)
				{
					_smtpDeliveryMethod = value;
					SaveSetting(SMTP_DELIVERY_METHOD, (int)_smtpDeliveryMethod);
				}
			}
		}

		[Category("Reporting Information"), Description("Custom pickup directory location.")]
		public string SmtpPickupDirectoryLocation
		{
			get { return _smtpPickupDirectoryLocation; }
			set
			{
				if (_smtpPickupDirectoryLocation != value)
				{
					_smtpPickupDirectoryLocation = value;
					SaveSetting(SMTP_PICKUP_DIRECTORY, _smtpPickupDirectoryLocation);
				}
			}
		}

		[Category("Reporting Information"), Description("Sender's email address.")]
		public string MailFrom
		{
			get { return _mailFrom; }
			set
			{
				if (_mailFrom != value)
				{
					_mailFrom = value;
					SaveSetting(MAIL_FROM, _mailFrom);
				}
			}
		}

		[Category("Reporting Information"), Description("Reciever's email addresses, separated by a comma (\",\")")]
		public string MailTo
		{
			get { return _mailTo; }
			set
			{
				if (_mailTo != value)
				{
					_mailTo = value;
					SaveSetting(MAIL_TO, _mailTo);
				}
			}
		}

		[Category("Reporting Information"), Description("Send the reports as HTML?")]
		public bool SendAsHTML
		{
			get { return _sendAsHtml; }
			set
			{
				if (_sendAsHtml != value)
				{
					_sendAsHtml = value;
					SaveSetting(SEND_AS_HTML, _sendAsHtml);
				}
			}
		}


		[Category("Reporting Information"), Description("Should the system send an email every time the service's status changes?")]
		public bool SendServiceStatus
		{
			get { return _sendServiceStatus; }
			set
			{
				if (_sendServiceStatus != value)
				{
					_sendServiceStatus = value;
					SaveSetting(SEND_SERVICE_STATUS, _sendServiceStatus);
				}
			}
		}

		[Category("Reporting Information"), Description("Frequency on which task reports are sent: Never, OnErrors, Always.")]
		public SendTaskReportModes SendTaskReport
		{
			get { return _sendTaskReport; }
			set
			{
				if (_sendTaskReport != value)
				{
					_sendTaskReport = value;
					SaveSetting(SEND_TASK_REPORT, (int)_sendTaskReport);
				}
			}
		}

		[Category("Reporting Information"), Description("Send a daily  report?")]
		public SendDailyReportModes SendDailyReport
		{
			get { return _sendDailyReport; }
			set
			{
				if (_sendDailyReport != value)
				{
					_sendDailyReport = value;
					SaveSetting(SEND_DAILY_REPORT, (int)_sendDailyReport);
				}
			}
		}
		#endregion

		#region "Other properties"
		[Browsable(false)]
		public TaskConfigurationCollection Tasks
		{
			get { return TaskConfigurationCollection.Instance; }
		}
		#endregion

		#region "Configuration I/O access methods"
		private string GetSetting(string key, object defaultValue)
		{
			string rc;
			string query;


			query = String.Format("SELECT ISNULL((SELECT cfgValue FROM sysConfig WHERE cfgKey={0}), {1})",
					SqlConvert.SqlString(key),
					SqlConvert.SqlString(defaultValue));
			rc = ExecuteScalar(query).ToString();

			return rc;
		}

		private void SaveSetting(string key, object value)
		{
			string query;
			int cfgId;

			query = String.Format("SELECT ISNULL((SELECT cfgId FROM sysConfig WHERE cfgKey={0}),0)", SqlConvert.SqlString(key));
			cfgId = (int)ExecuteScalar(query);
			if (cfgId == 0)
			{
				if ((value != null) && (value.ToString().Length != 0))
				{
					query = String.Format("INSERT INTO sysConfig(cfgKey,cfgValue) VALUES ({0},{1})",
																											SqlConvert.SqlString(key),
																											SqlConvert.SqlString(value));
					ExecuteNonQuery(query);
				}
			}
			else
			{
				if ((value == null) || (value.ToString().Length == 0))
					query = String.Format("DELETE FROM sysConfig WHERE cfgId={0}", cfgId);
				else
					query = String.Format("UPDATE sysConfig SET cfgValue={0} WHERE cfgId={1}", SqlConvert.SqlString(value), cfgId);
				ExecuteNonQuery(query);
			}
		}
		#endregion

		#region "Data Access Methods"
		private void ExecuteNonQuery(string query)
		{
			SqlConnection cn;
			SqlCommand cmd;

			cn = new SqlConnection(Properties.Settings.Default.ConnectionString);

			try
			{
				cn.Open();
				cmd = cn.CreateCommand();
				cmd.CommandText = query;
				cmd.ExecuteNonQuery();
				cmd.Connection = null;
				cmd = null;
			}
			finally
			{
				cn.Close();
			}
		}

		private object ExecuteScalar(string query)
		{
			SqlConnection cn;
			SqlCommand cmd;
			object rc = null;

			cn = new SqlConnection(Properties.Settings.Default.ConnectionString);

			try
			{
				cn.Open();
				cmd = cn.CreateCommand();
				cmd.CommandText = query;
				rc = cmd.ExecuteScalar();
				cmd.Connection = null;
				cmd = null;
			}
			finally
			{
				cn.Close();
			}

			return rc;
		}

		private DataTable ExecuteDataTable(string query)
		{
			SqlDataAdapter da;
			DataSet rc;

			da = new SqlDataAdapter(query, Properties.Settings.Default.ConnectionString);
			rc = new DataSet();
			da.Fill(rc);
			return rc.Tables.Count != 0 ? rc.Tables[0] : null;
		}

		private DataSet ExecuteDataSet(string query)
		{
			SqlDataAdapter da;
			DataSet rc;

			da = new SqlDataAdapter(query, Properties.Settings.Default.ConnectionString);
			rc = new DataSet();
			da.Fill(rc);
			return rc;
		}
		#endregion

	}
}
